package com.example.demo.test;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * <p>
 * Description:
 * 参照spring获取实例，spring是项目启动之前将各实例初始化，本文为主动调用一次实例化一个，自此之后不再实例化相同的对象，不够完善，简单的实例化demo,不用内部类，使用抽象类代码更加优化和简洁
 * </p>
 * 
 * @author 肖鑫
 * @date 2018年11月22日
 * 
 */
public class ManagerFactory {

	// 参照大部分框架中bean创建方式，默认为true(单列模式)
	public boolean singleton = true;

	public ManagerFactory() {
	}

	public ManagerFactory(boolean singleton) {
		this.singleton = singleton;
	}

	public boolean isSingleton() {
		return singleton;
	}

	public void setSingleton(boolean singleton) {
		this.singleton = singleton;
	}

	public static class InstanceFactory {
		private static InstanceFactory factory = new InstanceFactory();
		private ManagerFactory bean;
		private final static Map<Class<?>, ManagerFactory> factoryBeanObjectCache = new ConcurrentHashMap<>(); // 大部分框架中也是同过map来维护实例

		public ManagerFactory createBean(Class<? extends ManagerFactory> cls) throws Exception {
			this.bean = factoryBeanObjectCache.get(cls);
			if (this.bean == null) {
				this.bean = new ManagerFactory();
				createBean(this.bean, cls);
			}
			return this.bean;
		}

		protected void createBean(ManagerFactory bean, Class<? extends ManagerFactory> cls) throws Exception {
			if (bean.isSingleton()) {
				bean = factoryBeanObjectCache.remove(cls);
			}
			if (bean == null) {
				bean = cls.getConstructor().newInstance(); // 大部分框架中的bean创建也是通过构造器来创建实例，其他使用反射来获取实例的方法来讲内部也是通过调用构造器newInstance()方法。
			}
			bean = factoryBeanObjectCache.put(cls, bean); // 如果重复key,返回旧值
			if (bean == null) {
				this.bean = factoryBeanObjectCache.get(cls);
			}
		}

		protected static void clearCacheInstance() {
			factoryBeanObjectCache.clear();
		}

		public static ManagerFactory getBean(Class<? extends ManagerFactory> cls) throws Exception {
			return factory.createBean(cls);
		}
	}

	public static ManagerFactory getInstance(Class<? extends ManagerFactory> cls) throws Exception {
		return InstanceFactory.getBean(cls);
	}

	@SuppressWarnings("unused")
	private void clearCacheInstance() {
		InstanceFactory.clearCacheInstance();
	}

}
